import Cesium from '../Ces/Cesium'

import WeCone from './WeCone'
import WeGridExtrusion from './WeGridExtrusion'
import WeImagertLayerProvider from './WeImageryLayerProvider'
import WeLengthWayManager from './WeLengthwaysManager'
import WeQueryCompute from './WeQueryCompute'
import WeSurfaceManager from './WeSurfaceManager'
import WeVolume from './WeVolume'
import WeWindCompute from './WeWindCompute'
import WeVoxelPrimitive from './WeVoxelPrimitive'
import WeDataProvider from './WeDataProvider'
import WeDisplay from './WeDisplay'
import WeGridMovable from './WeGridMovable'
import WeIsoSurface from './WeIsoSurface'
import WeImageryLayerPicker from './WeImageryLayerPicker'
import LayerManager from '../Layer/LayerManager'
import WeGridValue from './WeGridValue'
import WeWindStreamline from './WeWindStreamline'
import { WeGridMovableOptions } from './WeGridMovableStyle'

class WeImageryLayer extends Cesium.ImageryLayer {
  [x: string]: any
  _dataProvider: WeDataProvider
  private _display: WeDisplay
  _queryCompute: WeQueryCompute
  private _ready: boolean = false
  stopRendering: boolean = false
  private _mgr: LayerManager
  private _readyPromise
  private _volume: WeVolume
  private _lengthwaysManager: WeLengthWayManager
  private _surfaceManager: WeSurfaceManager
  private _voxelPrimitive: WeVoxelPrimitive
  private _cone: WeCone
  private _gridMovable: WeGridMovable
  private _gridExtrusion: WeGridExtrusion
  private _isoSurface: WeIsoSurface
  private _picker: WeImageryLayerPicker | undefined | null
  private _gridValue: WeGridValue | undefined | null
  private _windStreamline: WeWindStreamline
  private _loadingRef: number = 0
  private _submitRef: number = 0
  id: string
  constructor(options) {
    const imageryProvider = new WeImagertLayerProvider(options)
    super(imageryProvider, options)

    this._dataProvider = options.dataProvider
    this._dataProvider._imageryLayer = this
    this._display = options.display
    this._display.imageryLayer = this
    imageryProvider.createComputeCommand = (p1, p2, p3, p4) =>
      this._display.createComputeCommand(p1, p2, p3, p4)
    this._mgr = options.mgr
    this._readyPromise = Cesium.defer()
  }

  _createTextureWebGL(context, imagery) {
    return this._display._createTextureWebGL(context, imagery)
  }

  // get imageryProvider(){
  //   return this._imageryProvider
  // }

  // set imageryProvider(value) {
  //   this._imageryProvider = value
  //   this._readyPromise.resolve(this)
  // }

  get loadingRef() {
    return this._loadingRef
  }

  set loadingRef(value) {
    this._loadingRef = value
  }

  get submitRef() {
    return this._submitRef
  }

  set submitRef(value) {
    this._submitRef = value
  }

  get isLoading() {
    return this._loadingRef > 0 || this._submitRef > 0
  }

  get readyPromise() {
    return this._readyPromise.promise
  }

  get rectangle() {
    return this._rectangle || this._imageryProvider.rectangle
  }

  get dataProvider() {
    return this._dataProvider
  }

  get display() {
    return this._display
  }

  get picker() {
    if (!this._picker) {
      this._picker = new WeImageryLayerPicker({
        display: this.display,
      })
    }
    return this._picker
  }

  get ready() {
    return this._ready
  }

  set ready(value) {
    if (value && this._ready !== value) {
      this._ready = true
      this._readyPromise.resolve(this)
    }
  }

  showGridValue(options) {
    this._gridValue = this._gridValue?.destroy()
    if (options === false) {
      this._showGridValue = false
      return
    }
    this._gridValue = new WeGridValue({
      display: this.display,
      clampToGround: false,
      useGridEffect: true,
      ...options,
    })
  }

  get volume() {
    return this._volume || this._voxelPrimitive
  }

  get wind(): WeGridMovable {
    return this._gridMovable
  }

  get windStreamline(): WeWindStreamline {
    return this._windStreamline
  }

  get gridMovable(): WeGridMovable {
    return this._gridMovable
  }

  get lengthwaysManager() {
    if (this._ready && !Cesium.defined(this._lengthwaysManager)) {
      this._lengthwaysManager = new WeLengthWayManager({
        rectangle: this.rectangle,
        dataProvider: this.dataProvider,
        display: this.display,
      })
    }
    return this._lengthwaysManager
  }

  get surfaceManager() {
    if (this._ready && !Cesium.defined(this._surfaceManager)) {
      this._surfaceManager = new WeSurfaceManager({
        rectangle: this.rectangle,
        dataProvider: this.dataProvider,
        display: this.display,
      })
    }

    return this._surfaceManager
  }

  updateData(context, image1, image2) {
    if (this._isoSurface) {
      this._isoSurface.updateData(context, image1, image2)
    }

    if (this._windStreamline) {
      this._windStreamline.updateData(context, image1, image2)
    }

    this.display.updateData(context, image1, image2)
    if (this._picker) {
      this._picker.dirty = true
    }
  }

  addLengthways(options) {
    if (!this._ready || !this.display.valueDecoder.isSampler3D) {
      return undefined
    }

    let rectangle

    if (options instanceof Cesium.Rectangle) {
      rectangle = this.computeSubRectangle(options)
    } else {
      rectangle = this.rectangle
    }

    return this.lengthwaysManager.add({
      ...options,
      rectangle,
    })
  }

  removeLengthways(id = null) {
    if (Cesium.defined(this._lengthwaysManager)) {
      if (Cesium.defined(id)) {
        return this._lengthwaysManager.remove(id)
      }

      return this._lengthwaysManager.removeAll()
    }

    return false
  }

  computeSubRectangle(inRectangle) {
    if (!inRectangle) {
      return this.rectangle
    }
    const rectangle = Cesium.Rectangle.intersection(
      this.rectangle,
      inRectangle,
      new Cesium.Rectangle(),
    )

    return rectangle || this.rectangle
  }

  addPlanetVolume(options) {
    this.removeVolume()

    this._voxelPrimitive = new WeVoxelPrimitive({
      display: this.display,
      dataProvider: this.dataProvider,
      rectangle: this.rectangle,
      ...options,
    })
    return this._voxelPrimitive
  }

  addVolume(inRectangle, options = {}) {
    if (!this._ready || !this.display.valueDecoder.isSampler3D) {
      return undefined
    }

    this.removeVolume()

    if (Cesium.defined(inRectangle)) {
      const rectangle = Cesium.Rectangle.intersection(
        this.rectangle,
        inRectangle,
        new Cesium.Rectangle(),
      )
      if (!rectangle) return undefined
      this._volume = WeVolume.build({
        display: this._display,
        dataProvider: this.dataProvider,
        rectangle,
        ...options,
      })
    } else {
      this._volume = WeVolume.build({
        display: this._display,
        dataProvider: this.dataProvider,
        rectangle: this.rectangle,
        ...options,
      })
    }

    return this._volume
  }

  removeVolume() {
    const succeed = Cesium.defined(this._volume) || Cesium.defined(this._voxelPrimitive)
    this._volume = this._volume && this._volume.destroy()
    this._voxelPrimitive = this._voxelPrimitive && this._voxelPrimitive.destroy()
    return succeed
  }

  addSurface(inRectangle) {
    if (!this._ready) {
      return undefined
    }

    const options = {
      display: this.display,
      dataProvider: this.dataProvider,
      clampToGround: false,
    }

    let rectangle
    if (inRectangle instanceof Cesium.Rectangle) {
      rectangle = inRectangle
    } else {
      rectangle = inRectangle?.rectangle ?? this.rectangle
      options.clampToGround = inRectangle && inRectangle.clampToGround
    }

    return this.surfaceManager.add({
      ...options,
      rectangle,
    })
  }

  removeSurface(id = null) {
    if (Cesium.defined(this._surfaceManager)) {
      if (Cesium.defined(id)) {
        return this._surfaceManager.remove(id)
      }

      return this._surfaceManager.removeAll()
    }

    return false
  }

  addCone(options) {
    this.removeCone()
    this._cone = new WeCone({
      display: this.display,
      dataProvider: this.dataProvider,
      rectangle: this.rectangle,
      ...options,
    })

    return this._cone
  }

  removeCone() {
    this._cone = this._cone && this._cone.destroy()
  }

  addWind(options) {
    this.removeWind()

    if (options.clampToGround === true) {
      const wind: any = new WeWindCompute({
        ...options,
        display: this.display,
        dataProvider: this.dataProvider,
      })
      this._gridMovable = wind
    } else {
      this.addGridMovable(options)
    }

    return this.wind
  }

  removeWind() {
    this.removeGridMovable()
  }

  addIsoSurface(options): WeIsoSurface {
    this.removeIsoSurcae()
    this._isoSurface = new WeIsoSurface({
      display: this.display,
      dataProvider: this.dataProvider,
      rectangle: this.rectangle,
      taskProcessorPool: this._mgr.taskProcessorPool,
      ...options,
    })
    return this._isoSurface
  }

  removeIsoSurcae() {
    this._isoSurface = this._isoSurface && this._isoSurface.destroy()
  }

  addWindStreamline(options): WeWindStreamline {
    this.removeWindStreamline()
    this._windStreamline = new WeWindStreamline({
      display: this.display,
      dataProvider: this.dataProvider,
      rectangle: this.rectangle,
      taskProcessorPool: this._mgr.taskProcessorPool,
      ...options,
    })
    return this._windStreamline
  }

  removeWindStreamline() {
    this._windStreamline = this._windStreamline && this._windStreamline.destroy()
  }

  addGridExtrusion(options) {
    this.removeGridExtrusion()
    this._gridExtrusion = new WeGridExtrusion({
      ...options,
      display: this.display,
    })

    return this._gridExtrusion
  }

  removeGridExtrusion() {
    this._gridExtrusion = this._gridExtrusion?.destroy()
  }

  addGridMovable(options: WeGridMovableOptions) {
    this.removeGridMovable()
    this._gridMovable = new WeGridMovable(
      options,
      this.display,
      this.dataProvider,
      this._mgr,
    )
  }

  removeGridMovable() {
    this._gridMovable = this._gridMovable?.destroy()
  }

  query(cartographic) {
    if (this._ready) {
      if (!this._queryCompute) {
        this._queryCompute = new WeQueryCompute({
          display: this.display,
        })
        this._queryCompute._textureUniform = this.display.weTextureUniform
      }

      const rectangle = this.rectangle

      if (Cesium.Rectangle.contains(rectangle, cartographic)) {
        return this._queryCompute.query(
          new Cesium.Cartesian3(
            (cartographic.longitude - rectangle.west) / rectangle.width,
            (cartographic.latitude - rectangle.south) / rectangle.height,
            0.0,
          ),
        )
      }
    }

    return Promise.resolve(null)
  }

  update(frameState) {
    if (this.stopRendering) return

    this.dataProvider.update(frameState)
    this.display.update(frameState)

    if (!this._ready || !this._imageryProvider.ready) {
      return
    }

    this._cone?.update(frameState)
    this._surfaceManager?.update(frameState)
    this._gridExtrusion?.update(frameState)
    this._gridMovable?.update(frameState)
    this._voxelPrimitive?.update(frameState)
    this._isoSurface?.update(frameState)
    this._volume?.update(frameState)
    this._lengthwaysManager?.update(frameState)
    this._queryCompute?.update(frameState)
    this._gridValue?.update(frameState)
    this._windStreamline?.update(frameState)

    if (this._picker) {
      if (this.display.shouldAnime) {
        this._picker.dirty = true
      }
      this._picker.update(frameState)
    }
  }

  destroy() {
    this._lengthwaysManager = this._lengthwaysManager?.destroy()
    this._surfaceManager = this._surfaceManager?.destroy()
    this._dataProvider = this._dataProvider?.destroy()
    this._display = this._display?.destroy()
    this._queryCompute = this._queryCompute?.destroy()
    this._gridValue = this._gridValue?.destroy()
    this._picker?.destroy()
    this.removeVolume()
    this.removeWind()
    this.removeGridExtrusion()
    this.removeGridMovable()
    this.removeIsoSurcae()
    this.removeWindStreamline()
    this.removeCone()
    return Cesium.destroyObject(this)
  }

  isdestroyed() {
    return false
  }
}

export default WeImageryLayer
